/*------------------------------------------------------------------------------
 *  SJunction - Schematic Junction object  
 *  
 *  August 2009, Forhad Ahmed
 *------------------------------------------------------------------------------
 */

package schematic;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.Vector;

import vector.vector;


public class SJunction extends SObject {

    public SJunction(int cx, int cy) {
        super();
        initJunction(cx, cy);
    }
    
    public SJunction(int cx, int cy, int i) {
        super(i);
        //initJunction(cx, cy);
    }
    
    public void initJunction(int cx, int cy)  {
        p = new Point(cx, cy);
        edges = new vector("junction-edge");
    }
    
    
    /*
     * Return a copy of the object to be used for checkpointing
     */
    public SObject checkpoint(int action) {
        SJunction checkpoint;
        
        checkpoint = new SJunction(p.x, p.y, id);
        checkpoint.original = this;
        
        if (action == Schematic.CHECKPOINT_MOD) {
            checkpoint.p = new Point(p.x, p.y);
            checkpoint.edges = edges.clone();
        }
        
        return checkpoint;
    }
    
    
    /*
     * Revert this modified object back to it's checkpointed state
     */
    public void revert(SObject object) {
        SJunction checkpoint;
        checkpoint = (SJunction) object;
         
        p.x = checkpoint.p.x;
        p.y = checkpoint.p.y;
        edges = checkpoint.edges;
    }
   
    
    /*
     * 
     */
    public SObject diff(SObject junction) {
        SJunction original;
        original = (SJunction) junction;
        
        if (checkpoint == Schematic.CHECKPOINT_MOD) {
            p.x = original.p.x - p.x; p.y = original.p.y - p.y;
            edges = this.edges;
            new_edges = original.edges.clone();
        }
        
        return this;
    }
    
    public void rpatch(SObject object, Schematic schematic) {
        SJunction diff;
        diff = (SJunction) object;
        
        if (diff.checkpoint == Schematic.CHECKPOINT_MOD) {
            move(-diff.p.x, -diff.p.y);
            edges = diff.edges;
        } else if (diff.checkpoint == Schematic.CHECKPOINT_ADD) {
            schematic.remove_internal(diff.original);
        } else if (diff.checkpoint == Schematic.CHECKPOINT_DEL) {
            schematic.add_internal(diff.original);
        }
        
    }
    
    
    public void patch(SObject object, Schematic schematic) {
        SJunction diff;
        diff = (SJunction) object;
       
        if (diff.checkpoint == Schematic.CHECKPOINT_MOD) {
            move(diff.p.x, diff.p.y);
            edges = diff.new_edges;
        } else if (diff.checkpoint == Schematic.CHECKPOINT_ADD) {
            schematic.add_internal(diff.original);
        } else if (diff.checkpoint == Schematic.CHECKPOINT_DEL) {
            schematic.remove_internal(diff.original);
        }
        
    }
    
    public boolean hit(int sx, int sy) {
        hpoint.x = Schematic.c2s(p.x);
        hpoint.y = Schematic.c2s(p.y);
        
        if (hpoint.distance((double)sx, (double)sy) < 5) {
            return true;
        }
        return false;
    }
    
    public SJunction suggest(int sx, int sy) {
        SJunction r = null;
        
        spoint.x = Schematic.c2s(p.x);
        spoint.y = Schematic.c2s(p.y);
        if (spoint.distance((double)sx, (double)sy) < 10) {
            r = this;
        }
        
        return r;
    }
    
    public Point place(int x, int y) {
        int cx, cy, dx, dy;
        cx = p.x; cy = p.y;
        dx = x - cx; dy = y - cy;
        p.x = x;  p.y = y;
        d.x = dx; d.y = dy;
        return d;
    }
    
    public void move(int dx, int dy) {
        place(p.x + dx, p.y + dy);
    }
    
    public Vector dependents() {
        int index;
        SEdge edge;
        
        dependents.clear();
        
        for (index = 0; index < edges.size(); index++) {
            edge = (SEdge) edges.get(index);
            if (!dependents.contains(edge)) {
                dependents.add(edge);
            }
        }
        
        return dependents;
    }
    
    
    /*
     * If the junction is orphaned, then we only return a valid box (i.e this
     * junction is a candidate for selection by box) if the edge that is linked
     * with this junction is selected.  *This would require that edges are 
     * selected before junctions* when multiple objects are being selected 
     * together in the canvas so that junctions can make a decision on whether 
     * it can be selected or not.
     */
    public Rectangle getBoundingBox() {
        SEdge edge;
        
        box.x = p.x; box.y = p.y;
        box.width = 0; box.height = 0;

        return box; 
    }
    
    
    /*
     * At least one of the junction's edges must be marked selected in order for
     * this junction to be selectable.
     */
    public boolean selectable() {
        int index;
        SEdge edge;
        
        if (!mark_selected) return false;
        
        for (index = 0; index < edges.size(); index++) {
            edge = (SEdge) edges.get(index);
            /*
             * We want at least one of it's edges to be *selected* and not just
             * mark_selected in order for this junction to be selectable
             */
            if (edge.selected) return true;
        }
        
        return false;
    }
    
    
    /*
     * A junction is deletable when all of its incident edges are marked deleted
     */
    public boolean deletable() {
        int index;
        SEdge edge;
        
        for (index = 0; index < edges.size(); index++) {
            edge = (SEdge) edges.get(index);
            if (!edge.mark_deleted) return false;
        }
        
        return true;
    }
    
    
    public void rotate(int dir, int x, int y) {
        int cos, sin;
        int cx, cy, tx, ty;
        
        cos = (int) Math.round(Math.cos(dir * Math.PI/2));
        sin = (int) Math.round(Math.sin(dir * Math.PI/2));
        
        /*
         * Rotate the center around the input point (x, y);
         */
        cx = p.x; cy = p.y; cx -= x; cy -= y; tx = cx; ty = cy; 
        cx = tx * cos + ty * sin;  cy = -tx * sin + ty * cos;
        cx += x; cy += y; p.x = cx; p.y = cy;
    }
    
    public Point2D.Float center() {
        com.x = p.x; 
        com.y = p.y;
        
        return com;
    }
    
    public void draw(Graphics g, Schematic schematic) {
        int sx, sy;
        sx = Schematic.c2s(p.x);
        sy = Schematic.c2s(p.y);
        
        
        if (selected) {
            g.setColor(schematic.selection_color);
        } else {
            g.setColor(Color.orange);
        }
        
        g.fillRect(sx - 1, sy - 1, 3, 3);
    }
    
    
    /*
     * Dump the entire object
     */
    public String dump() {
        int index;
        SEdge edge;
        
        String s = "";
        s += super.toString() + " ";
        s += "[" + p.x + "," + p.y + "]" + " ";
        s += "EDGES: [ ";
        for (index = 0; index < edges.size(); index++) {
        edge = (SEdge) edges.get(index);
        s += edge.id + ", ";
        }
        s += "]";
        return s;
    }
    
    
    public String typeString() {
        return "[junction]";
    }
    
    
    public Point  p;
    public vector edges;
    
    public vector new_edges;
}
